package algorithm.winnow;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import stemmer.NullStemmer;
import stemmer.Stemmer;
import utility.file.TextFile;
import wordnet.IWordnetOperator;
import wordnet.NullWordnetOperator;
import words.extractor.WordsExtractor;
import algorithm.measures.BinaryConfusionMatrix;
import core.Main;



public class TrainingWinnowCommittee {
	
	private Map<String, Double> _expertToWeight;
	private double _thresholdCoefficient;
	private String _category;
	private Stemmer _stemmer;
	private BinaryConfusionMatrix _matrix;
	private IWordnetOperator _wordnet;
	public TrainingWinnowCommittee(String category, double thresholdCoefficient){
		this(category, thresholdCoefficient, new NullWordnetOperator(), new NullStemmer());
	}
	
	public TrainingWinnowCommittee(String category, double thresholdCoefficient, IWordnetOperator catcher, Stemmer stemmer) {
		_category = category;
		_expertToWeight = new HashMap<String,Double>();
		_thresholdCoefficient = thresholdCoefficient;
		_stemmer = stemmer;
		_wordnet = catcher;
		_matrix = new BinaryConfusionMatrix();
	}

	public String category(){
		return _category;
	}

	

	public boolean trainWith(String question, boolean positiveExample) {
		Set<String> positivePredictors = new HashSet<String>();
		List<String> tokens = new WordsExtractor(_wordnet,_stemmer).extractFromUsing(question,Main.N_WORDS);
		double evaluation = 0;
		for (int i=0; i<tokens.size(); i++) {
			String each = tokens.get(i);
			double weight = 0;
			if(_expertToWeight.get(each)!=null){
				weight = _expertToWeight.get(each);
				positivePredictors.add(each);
			}
			evaluation+=weight;
		}
		
		boolean positivePrediction = (evaluation>=currentThreshold());
		refreshWeightsUsing(positivePredictors, positivePrediction, positiveExample);

		if(positiveExample){
			for (String each : tokens) {
				if (!_expertToWeight.containsKey(each)) _expertToWeight.put(each, (double)1);
			}
			if(positivePrediction) {
				_matrix.addTruePositives(1);
				return true;
			}
			else _matrix.addFalseNegatives(1);
		}
		
		if(!positiveExample){
			if(positivePrediction) _matrix.addFalsePositives(1);
			else {
				_matrix.addTrueNegatives(1);
				return true;
			}
		}
		return false;
	}

	private void refreshWeightsUsing(Set<String> positiveExpertsEvaluators, boolean positivePrediction, boolean positiveExample) {	
		if(positivePrediction&&positiveExample) return;
		if(!positivePrediction&&!positiveExample) return;
		

		for (String each : positiveExpertsEvaluators) {
			double weight = _expertToWeight.get(each);
			if (!positiveExample) weight = weight/2;
			else weight = 2*weight;
			
			_expertToWeight.put(each, weight);
		}		
	}

	private double currentThreshold() {
//		double threshold = _expertToWeight.size();
		double threshold = 0;
		for (String each : _expertToWeight.keySet()) {
			double weight = _expertToWeight.get(each);
			threshold+=weight;
		}
		
		return threshold*_thresholdCoefficient;
	}

	public TestWinnowCommittee tester() {
		TestWinnowCommittee committee = new TestWinnowCommittee(_category,Main.TEST_WINNOW_COEFFICIENT,_wordnet,_stemmer);
		for (String each : _expertToWeight.keySet()) {
			committee.put(each, _expertToWeight.get(each));
		}
		return committee;
	}

	public void writeResultsForOn(int counter, String name, TextFile file) {
		_matrix.writeResultsForOn(counter, name, file);
	}

}
